<template>
  <div class="bg">
    <transition-group class="view flex flex-wrap justify-center items-center" name="list" tag="div">
      <div v-for="i in list" :key="i.inx">
        <div :class="['box', currentClassName(i.inx)]">{{ i.item }}</div>
        <div class="text">
          <div class="current" v-if="current == i.inx">current</div>
          <div class="target" v-if="target == i.inx">target</div>
          <div class="min" v-if="min == i.inx">min</div>
        </div>
      </div>
    </transition-group>
    <dw-row type="flex" class="row">
      <dw-col :span="24" class="text-center">执行次数：{{ times }}</dw-col>
    </dw-row>
    <dw-row class="row" type="flex" justify="center" :gutter="20">
      <dw-col class="text-center" :lg="2" :sm="6">
        <dw-button type="primary" @click="setSort('bubbleSort')">冒泡</dw-button>
      </dw-col>
      <dw-col class="text-center" :lg="2" :sm="6">
        <dw-button type="primary" @click="setSort('selectionSort')">选择</dw-button>
      </dw-col>
      <!-- <dw-col class="text-center" :lg="2" :sm="6">
        <dw-button type="primary" @click="setSort('selectionSort')">选择</dw-button>
      </dw-col> -->
    </dw-row>
    <dw-row type="flex" justify="center" :gutter="20">
      <dw-col class="text-center" :lg="2" :sm="12">
        <dw-button type="success" v-if="!doing" @click="start">{{ this.times == 0 ? "开始" : "继续" }}</dw-button>
        <dw-button type="error" v-else @click="stop">暂停</dw-button>
      </dw-col>
      <dw-col class="text-center" :lg="2" :sm="12">
        <dw-button type="warning" @click="shuffle">随机</dw-button>
      </dw-col>
    </dw-row>
  </div>
</template>

<script>
// import heartLike from "@/components/icon/heart/heartLike";
import { swap, sleep, generatorStep } from "./methods";
import _ from "lodash";

export default {
  components: {
    // heartLike,
  },
  data() {
    return {
      list: [],
      classList: ["current", "target", "min"],
      times: 0,
      // class状态
      current: null,
      target: null,
      min: null,

      steps: null,
      doing: false,
    };
  },
  created() {
    const arr = [3, 5, 44, 38, 15, 47, 26, 36, 27, 2, 46, 4, 19, 50, 48];
    this.list = arr.map((item, inx) => {
      return {
        item,
        inx,
      };
    });
  },
  methods: {
    currentClassName(inx) {
      let name = [];
      this.classList.forEach((i) => {
        if (this[i] == inx) name.push(i);
      });
      let res = name.join("-");
      return `${res}-bg`;
    },
    // 打乱
    shuffle() {
      this.list = _.shuffle(this.list);
      this.reset();
    },
    // 复原
    reset() {
      this.times = 0;
      this.current = null;
      this.target = null;
      this.min = null;
      this.steps = null;
      this.doing = false;
    },
    // 开始
    async start() {
      if (!this.steps) return;
      this.doing = true;
      while (this.doing) {
        this.next();
        await sleep(800);
      }
    },
    // 暂停
    stop() {
      this.doing = false;
    },
    // 执行过程
    async next() {
      const next = this.steps.next();
      if (!next.done) {
        await next.value();
      } else {
        this.current = null;
        this.target = null;
        this.min = null;
        this.stop();
      }
    },
    // 设置排序规则
    setSort(sort) {
      this.reset();
      const len = this.list.length;
      let stepList = [];
      // 调用排序
      const arr = this.list.map((i) => i.item);
      this[sort](arr);
    },
    // 冒泡
    bubbleSort(arr) {
      const len = arr.length;
      const stepList = [];
      for (let i = 0; i < len - 1; i++) {
        for (let j = 0; j < len - 1 - i; j++) {
          [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
          stepList.push(this.bubbleSortProcess(j, j + 1));
        }
      }
      this.steps = generatorStep(stepList);
    },
    // 冒泡排序主要执行内容
    bubbleSortProcess(i, j) {
      return async () => {
        this.current = this.list[i].inx;
        this.target = this.list[j].inx;
        this.times++;
        await sleep(300);
        if (this.list[i].item > this.list[j].item) {
          swap(this.list, i, j);
          await sleep(300);
        }
      };
    },

    // 选择排序
    selectionSort(arr) {
      const len = arr.length;
      const stepList = [];
      let minInx;
      for (let i = 0; i < len - 1; i++) {
        minInx = i;
        for (let j = i + 1; j < len; j++) {
          // 找到最小的数，并保存索引
          if (arr[j] < arr[minInx]) {
            minInx = j;
          }
          stepList.push(this.selectionSortProcess(i, j, minInx));
        }
        [arr[i], arr[minInx]] = [arr[minInx], arr[i]];
        stepList.push(this.selectionSortProcess(i, null, minInx));
      }
      this.steps = generatorStep(stepList);
    },
    // 选择排序主要执行内容
    selectionSortProcess(i, j, min) {
      return async () => {
        this.current = this.list[i].inx;
        this.target = j ? this.list[j].inx : null;
        this.min = this.list[min].inx;
        this.times++;
        await sleep(300);
        if (j == null) {
          swap(this.list, i, min);
          await sleep(300);
        }
      };
    },

    // 快速排序
    quickSort(arr, left, right) {
      let len = arr.length;
      let partitionIndex;

      left = typeof left != "number" ? 0 : left;
      right = typeof right != "number" ? len - 1 : right;

      if (left < right) {
        partitionIndex = this.partition(arr, left, right);
        this.quickSort(arr, left, partitionIndex - 1);
        this.quickSort(arr, partitionIndex + 1, right);
      }
      return arr;
    },
    // 分区操作
    partition(arr, left, right) {
      let midIndex = left;
      let index = left + 1;
      for (let i = index; i <= right; i++) {
        // 如果当前值比基准值小。则放在左边
        if (arr[i] < arr[midIndex]) {
          [arr[i], arr[index]] = [arr[index], arr[i]];
          // 记录小于基准值的数量
          index++;
        }
        // 结束之后，把基准值放在小于他的右边
        [arr[midIndex], arr[index - 1]] = [arr[index - 1], arr[midIndex]];
        return index - 1;
      }
    },
  },
};
</script>

<style lang="less" scoped>
.bg {
  width: 100%;
  height: 50vh;
}
.list-move {
  transition: transform 0.3s;
}
.view {
  margin: 5em 0 5em;
}
@media screen and (max-width: 768px) {
  .view {
    margin: 1em 0 1em;
  }
}
.box {
  width: 2em;
  height: 2em;
  text-align: center;
  line-height: 2em;
  background: #7f8c8d;
  color: #fff;
  font-size: 2em;
  letter-spacing: 2px;
  margin: 0 0.5em;
  border-radius: 0.3em;
}
.text {
  text-align: center;
  width: 100%;
  height: 4em;
}
.row {
  padding: 10px 0;
}

// 状态
.current {
  color: @dw-color-success;
}
.target {
  color: @dw-color-danger;
}
.min {
  color: @dw-color-primary;
}
.current-bg {
  background: @dw-color-success;
}
.target-bg {
  background: @dw-color-danger;
}
.min-bg {
  background: @dw-color-primary;
}
.current-target-bg {
  background: linear-gradient(to right, @dw-color-success 50%, @dw-color-danger 50%);
}
.current-min-bg {
  background: linear-gradient(to right, @dw-color-success 50%, @dw-color-primary 50%);
}
.target-min-bg {
  background: linear-gradient(to right, @dw-color-danger 50%, @dw-color-primary 50%);
}
</style>
